#include <soar.h>

#include "common.h"

#define	DB_CONNECT_NUM		3	

struct thrd_ctl
{
    unsigned int thrd_id;
	int thrd_idx;
    ORAPROC db;
};
static struct thrd_ctl a_thrd_ctl[DB_CONNECT_NUM];

int insert(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    char buf[BUFFER_SIZE];
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf,
            "insert into my_emp values(:0, sysdate, :1, :2, :3, :4, :5)");
    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    dbc_bind_int64(&bind, 0, 100*(thrd_idx+1));
    dbc_bind_char(&bind, 1, "职员100", 20);
    dbc_bind_char(&bind, 2, "8", 1);
    dbc_bind_int(&bind, 3, 34);
    dbc_bind_varchar(&bind, 4, "中国");
    dbc_bind_varchar(&bind, 5, "岳阳楼记－范仲淹");
    res=oraproc_exec_ex(thrd_ctl->db, buf, &bind, 6);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
                thrd_idx, __func__, res); 
        return(-1);
    }
    printf("Thrd(%d) %s succeed\n", thrd_idx, __func__);
    printf("==================================================\n");

    return(0);
}/*}}}*/

int delete(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    char buf[BUFFER_SIZE];
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf,
            "delete from my_emp where empno=:0");
    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    dbc_bind_int64(&bind, 0, 100*(thrd_idx+1));
    res=oraproc_exec_ex(thrd_ctl->db, buf, &bind, 1);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
                thrd_idx, __func__, res); 
        return(-1);
    }
    printf("Thrd(%d) %s succeed\n", thrd_idx, __func__);
    printf("==================================================\n");

    return(0);
}/*}}}*/

int update(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    char buf[BUFFER_SIZE];
    int64_t empno;
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf, "update my_emp set upd_ts=:0,resume=:1 where empno=:2");
    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    empno=random_int(1, 10);
    printf("Thrd(%d) update empno(%lld) upd_ts...\n",
            thrd_idx, empno);
    dbc_bind_varchar(&bind, 0, "20000101000000");
    dbc_bind_varchar(&bind, 1, "岳阳楼记－范仲淹");
    dbc_bind_int64(&bind, 2, empno);
    res=oraproc_exec_ex(thrd_ctl->db, buf, &bind, 3);
    if(res != ORA_OK && res != ORA_NO_DATA_FOUND)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
            thrd_idx, __func__, res);
        return(-1);
    }
    if(res == ORA_NO_DATA_FOUND)
    {
        printf("Thrd(%d) no data found\n", thrd_idx); 
        return(-1);
    }
    printf("Thrd(%d) %s succeed\n", thrd_idx, __func__);
    printf("==================================================\n");

    return(0);
}/*}}}*/

int query1(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    DBC_RSET rset;
    int request_row_num;
    struct my_emp my_emp;
    int row_idx;
    char buf[BUFFER_SIZE];
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf,
            "select * from my_emp where name=:0 order by empno asc");
    dbc_bind_char(&bind, 0, "职员1", sizeof(my_emp.name)-1);
    request_row_num=5;
    res=oraproc_query_ex(thrd_ctl->db, buf, &bind, 1,
            request_row_num, &rset);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
            thrd_idx, __func__, res);
        return(-1);
    }

    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    printf("Thrd(%d) 结果:\n", thrd_idx);
    for(row_idx=0; row_idx<rset.row_num; row_idx++)
    {
        my_emp.empno=dbc_col_export_int64(&rset, row_idx, 0);
        dbc_col_export_char(&rset, row_idx, 1, my_emp.upd_ts);
        dbc_col_export_char(&rset, row_idx, 2, my_emp.name);
        dbc_col_export_char(&rset, row_idx, 3, my_emp.duty);
        my_emp.age=dbc_col_export_int(&rset, row_idx, 4);
        dbc_col_export_char(&rset, row_idx, 5, my_emp.address);
        my_emp.resume=dbc_col_take_char(&rset, row_idx, 6);
        printf("%lld|%s|%s|%s|%d|%s|%s\n",
                my_emp.empno, my_emp.upd_ts, my_emp.name,
                my_emp.duty, my_emp.age, my_emp.address,
                my_emp.resume);
        FREE(my_emp.resume);
    }
    if(rset.query_flag == QUERY_BOTTOM)
        printf("Thrd(%d) 查询到底\n", thrd_idx);
    else
        printf("Thrd(%d) 查询中途，有下一页\n", thrd_idx);
    printf("==================================================\n");
    dbc_query_free(&rset);

    return(0);
}/*}}}*/

int query2(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    DBC_RSET rset;
    char buf[BUFFER_SIZE];
    int res;
    int count, sum;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf,
            "select count(*),sum(age) from my_emp where empno>:0");
    dbc_bind_int64(&bind, 0, 1);
    res=oraproc_query_ex(thrd_ctl->db, buf, &bind, 1, -1,
            &rset);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
            thrd_idx, __func__, res);
        return(-1);
    }
    count=dbc_col_export_int(&rset, 0, 0);
    sum=dbc_col_export_int(&rset, 0, 1);
    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    printf("Thrd(%d) 结果: %d %d\n", thrd_idx, count, sum);
    printf("==================================================\n");
    dbc_query_free(&rset);

    return(0);
}/*}}}*/

int query3(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    DBC_RSET rset;
    int row_idx;
    struct my_emp my_emp;
    int count;
    char buf[BUFFER_SIZE];
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf, "select duty,count(*) from my_emp where upd_ts between to_date(:0,'YYYYMMDDHH24MISS') and to_date(:1,'YYYYMMDDHH24MISS') group by duty order by duty desc");
    //sprintf(buf, "select duty,count(*) from my_emp where upd_ts between :1 and :2 group by duty order by duty desc");
    dbc_bind_varchar(&bind, 0, "20000101000000");
    dbc_bind_varchar(&bind, 1, "20100101000000");
    res=oraproc_query_ex(thrd_ctl->db, buf, &bind, 2, -1, &rset);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s fail, sqlcode:%d\n",
            thrd_idx, __func__, res);
        return(-1);
    }

    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    printf("Thrd(%d) 结果:\n", thrd_idx);
    for(row_idx=0; row_idx<rset.row_num; row_idx++)
    {
        dbc_col_export_char(&rset, row_idx, 0, my_emp.duty);
        count=dbc_col_export_int(&rset, row_idx, 1);
        printf("%s|%d\n", my_emp.duty, count);
    }
    printf("==================================================\n");
    dbc_query_free(&rset);

    return(0);
}/*}}}*/

int query4(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    int thrd_idx=thrd_ctl->thrd_idx;
    DBC_BIND bind;
    DBC_RSET rset;
    struct my_emp my_emp;
    struct my_salary my_salary;
    int row_idx;
    char buf[BUFFER_SIZE];
    int res;

    printf("Thrd(%d) %s\n", thrd_idx, __func__);

    sprintf(buf,
            "select a.empno,a.name,b.salary "
            "from my_emp a, my_salary b "
            "where a.empno=b.empno and a.duty=:0 "
            "order by a.empno asc");
    dbc_bind_char(&bind, 0, "3", 1);
    res=oraproc_query_ex(thrd_ctl->db, buf, &bind, 1, -1,
            &rset);
    if(res != ORA_OK)
    {
        printf("Thrd(%d) %s: fail, sqlcode:%d\n",
            thrd_idx, __func__, res);
        return(-1);
    }

    printf("Thrd(%d) SQL: %s\n", thrd_idx, buf);
    printf("Thrd(%d) 结果:\n", thrd_idx);
    for(row_idx=0; row_idx<rset.row_num; row_idx++)
    {
        my_emp.empno=dbc_col_export_int64(&rset, row_idx, 0);
        dbc_col_export_char(&rset, row_idx, 1, my_emp.name);
        my_salary.salary=dbc_col_export_double(&rset, row_idx, 2);
        printf("%lld|%s|%.2lf\n",
                my_emp.empno, my_emp.name, my_salary.salary);
    }
    printf("==================================================\n");
    dbc_query_free(&rset);

    return(0);
}/*}}}*/

void *thrd_func(struct thrd_ctl *thrd_ctl)
{/*{{{*/
    oraproc_begin_ex(thrd_ctl->db);

    if(insert(thrd_ctl) ||
            delete(thrd_ctl) ||
            update(thrd_ctl) ||
            query1(thrd_ctl) ||
            query2(thrd_ctl) ||
            query3(thrd_ctl) ||
            query4(thrd_ctl))
    {
        oraproc_rollback_ex(thrd_ctl->db);
    }
    else
    {
        oraproc_commit_ex(thrd_ctl->db);
    }

    oraproc_disconnect_ex(thrd_ctl->db);
    return(NULL);
}/*}}}*/

int main(int argc, char *argv[])
{/*{{{*/
    int res;
    int thrd_idx;

    if(oraproc_init())
    {
        printf("oraproc_init fail\n");
        return(-1);
    }

    for(thrd_idx=0; thrd_idx<DB_CONNECT_NUM; thrd_idx++)
    {
        if((res=oraproc_connect_ex("dbuser", "dbuser", NULL,
                        &a_thrd_ctl[thrd_idx].db))!= ORA_OK)
        {
            printf("connect(%d) fail, sqlcode:%d\n",
                    thrd_idx, res); 
            return(-1);
        }
        a_thrd_ctl[thrd_idx].thrd_idx=thrd_idx;
        if(thrd_create((THRD_FUNC_T)thrd_func,
                    (void *)&a_thrd_ctl[thrd_idx],
                    0, &a_thrd_ctl[thrd_idx].thrd_id))
        {
            printf("Thread create fail\n");
            return(-1);
        }
    }
    for(thrd_idx=0; thrd_idx<DB_CONNECT_NUM; thrd_idx++)
    {
        thrd_join(a_thrd_ctl[thrd_idx].thrd_id);
    }

    oraproc_clean();

    return(0);
}/*}}}*/
